#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stdarg.h"
#include "bsp_usart.h"
#include "gd32f10x.h"
#include "gd32f10x_eval.h"

#define ARRAYNUM(arr_nanme)      (uint32_t)(sizeof(arr_nanme) / sizeof(*(arr_nanme)))

__IO FlagStatus g_u1transfer_complete = RESET;
uint16_t usart1_dmarx_len = 0;
uint8_t usart0_RxBuffer[USART0_RX_DATA_LEN] = {0};
uint8_t usart0_TxBuffer[USART0_TX_DATA_LEN] = "\n\rUSART0 DMA interrupt receive and transmit example, please input 10 bytes:\n\r";

/*!
    \brief      configure DMA interrupt
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void usart0_nvic_config(void)
{
    nvic_irq_enable(DMA0_Channel3_IRQn, 0, 0);
    nvic_irq_enable(DMA0_Channel4_IRQn, 0, 1);
}

/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
void bsp_usart0_init(void)
{
    dma_parameter_struct dma_init_struct;
    /* enable DMA0 clock */
    rcu_periph_clock_enable(RCU_DMA0);
    /* initialize USART */
    gd_eval_com_init(EVAL_COM0, 115200);
    /*configure DMA0 interrupt*/
    usart0_nvic_config();
    
    /* deinitialize DMA channel3(USART0 tx) */
    dma_deinit(DMA0, DMA_CH3);
    dma_struct_para_init(&dma_init_struct);

    
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = (uint32_t)usart0_TxBuffer;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = ARRAYNUM(usart0_TxBuffer);
    dma_init_struct.periph_addr = ((uint32_t)&USART_DATA(USART0));
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA0, DMA_CH3, &dma_init_struct);
    
    /* deinitialize DMA channel4 (USART0 rx) */
    dma_deinit(DMA0, DMA_CH4);
    dma_struct_para_init(&dma_init_struct);

    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)usart0_RxBuffer;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = sizeof(usart0_RxBuffer);
    dma_init_struct.periph_addr = ((uint32_t)&USART_DATA(USART0));
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.memory_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA0, DMA_CH4, &dma_init_struct);
  
    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH3);
    dma_memory_to_memory_disable(DMA0, DMA_CH3);
    dma_circulation_enable(DMA0, DMA_CH4);//enable rx circular
    dma_memory_to_memory_disable(DMA0, DMA_CH4);
    
    /* USART DMA0 enable for reception */
    usart_dma_receive_config(USART0, USART_DENR_ENABLE);
    /* enable DMA0 channel4 transfer complete interrupt */
    dma_interrupt_enable(DMA0, DMA_CH4, DMA_INT_FTF);
    /* enable DMA0 channel4 */
    dma_channel_enable(DMA0, DMA_CH4);
    /* USART DMA0 enable for transmission */
    usart_dma_transmit_config(USART0, USART_DENT_ENABLE);
    /* enable DMA0 channel3 transfer complete interrupt */
    dma_interrupt_enable(DMA0, DMA_CH3, DMA_INT_FTF);
    /* enable DMA0 channel3 */
    dma_channel_enable(DMA0, DMA_CH3);
    
    /* waiting for the transfer to complete*/
    while(RESET == g_u1transfer_complete);
    
    g_u1transfer_complete = RESET;

    /* waiting for the transfer to complete*/
    while(RESET == g_u1transfer_complete);

//    printf("\n\r%s\n\r", rxbuffer);
}

/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
    usart_data_transmit(EVAL_COM0, (uint8_t)ch);
    while(RESET == usart_flag_get(EVAL_COM0, USART_FLAG_TBE));
    return ch;
}

/**
 * [USART0_DMA_Send 通过DMA向串口发送不定长度的数据]
 * @param pbuffer [数据的传递指针]
 * @param size    [数据的长度]
 */
void USART0_DMA_Send(uint8_t *pbuffer, uint32_t size)
{
	if(size > USART0_TX_DATA_LEN){
		return;
	}
	if(g_u1transfer_complete == RESET) //发送数据完成后才能开始发送
	{
		/* 设置DMA传输 */
		dma_channel_disable(DMA0, DMA_CH3);		/* 关闭DMA传输才可以进行设置 */
		dma_memory_address_config(DMA0,DMA_CH3, (uint32_t)(pbuffer));
		dma_transfer_number_config(DMA0,DMA_CH3, size);
		dma_channel_enable(DMA0, DMA_CH3);		/* 开启DMA传输 */
		g_u1transfer_complete = SET; //数据发送中
	}
}

void send_data_dma_u0(uint8_t data[], uint8_t num)
{
	uint8_t x = 0;
	for(x = 0; x < num; x++)
	{
		usart0_TxBuffer[x] = data[x];
	}
	USART0_DMA_Send(usart0_TxBuffer, num);
}

/**
 * [u0_printf printf 函数]
 */
void u0_printf(char* fmt,...)
{
	va_list ap;
	va_start(ap,fmt);
	vsprintf((char*)usart0_TxBuffer, fmt, ap);
	va_end(ap);
	USART0_DMA_Send(usart0_TxBuffer, strlen((const char*)usart0_TxBuffer));
}

